package com.ccteam.fluidmusic.fluidmusic.common.utils

import com.google.android.exoplayer2.*
import kotlin.math.max
import kotlin.math.min

/**
 *
 * @author Xiaoc
 * @since 2021/1/11
 *
 * 播放控制处理
 * 控制音乐播放处理的基本逻辑，转交给ExoPlayer
 */
class FluidMusicControlDispatcher: ControlDispatcher {

    private val window = Timeline.Window()

    private val fastForwardIncrementMs: Long
    private val rewindIncrementMs: Long

    companion object{
        const val DEFAULT_FAST_FORWARD_MS: Long = 15_000
        const val DEFAULT_REWIND_MS: Long = 5000

        fun seekToOffset(player: Player,offsetMs: Long){
            var positionMs: Long = player.currentPosition + offsetMs
            val durationMs: Long = player.duration
            if(durationMs != C.TIME_UNSET){
                positionMs = min(positionMs,durationMs)
            }
            positionMs = max(positionMs,0L)
            player.seekTo(player.currentWindowIndex,positionMs)
        }
    }

    constructor(): this(DEFAULT_FAST_FORWARD_MS,DEFAULT_REWIND_MS)

    constructor(fastForwardIncrementMs:Long,rewindIncrementMs:Long){
        this.fastForwardIncrementMs = fastForwardIncrementMs
        this.rewindIncrementMs = rewindIncrementMs
    }

    override fun dispatchPrepare(player: Player): Boolean {
        player.prepare()
        return true
    }

    override fun dispatchSetPlayWhenReady(player: Player, playWhenReady: Boolean): Boolean {
        player.playWhenReady = playWhenReady
        return true
    }

    override fun dispatchSeekTo(player: Player, windowIndex: Int, positionMs: Long): Boolean {
        player.seekTo(windowIndex,positionMs)
        return true
    }

    override fun dispatchPrevious(player: Player): Boolean {
        val timeline = player.currentTimeline
        if(timeline.isEmpty || player.isPlayingAd){
            return true
        }
        val windowIndex = player.currentWindowIndex
        timeline.getWindow(windowIndex,window)
        val previousWindowIndex = player.previousWindowIndex
        val isUnSeekLiveStream = window.isLive() && !window.isSeekable
        if(previousWindowIndex != C.INDEX_UNSET || isUnSeekLiveStream){
            player.seekTo(previousWindowIndex,C.TIME_UNSET)
        } else if(!isUnSeekLiveStream){
            player.seekTo(windowIndex,0)
        }
        return true
    }

    override fun dispatchNext(player: Player): Boolean {
        val timeline = player.currentTimeline
        if(timeline.isEmpty || player.isPlayingAd){
            return true
        }
        val windowIndex = player.currentWindowIndex
        timeline.getWindow(windowIndex,window)
        val nextWindowIndex = player.nextWindowIndex
        if(nextWindowIndex != C.INDEX_UNSET){
            player.seekTo(nextWindowIndex,C.TIME_UNSET)
        } else if(window.isLive() && window.isDynamic){
            player.seekTo(windowIndex,C.TIME_UNSET)
        }
        return true
    }

    override fun dispatchRewind(player: Player): Boolean {
        if(isRewindEnabled && player.isCurrentWindowSeekable){
            seekToOffset(player,-rewindIncrementMs)
        }
        return true
    }

    override fun dispatchFastForward(player: Player): Boolean {
        if(isFastForwardEnabled && player.isCurrentWindowSeekable){
            seekToOffset(player,fastForwardIncrementMs)
        }
        return true
    }

    override fun dispatchSetRepeatMode(player: Player, repeatMode: Int): Boolean {
        player.repeatMode = repeatMode
        return true
    }

    override fun dispatchSetShuffleModeEnabled(
        player: Player,
        shuffleModeEnabled: Boolean
    ): Boolean {
        player.shuffleModeEnabled = shuffleModeEnabled
        return true
    }

    override fun dispatchStop(player: Player, reset: Boolean): Boolean {
        if(reset){
            player.stop()
            player.clearMediaItems()
        } else {
            player.stop()
        }
        return true
    }

    override fun dispatchSetPlaybackParameters(
        player: Player,
        playbackParameters: PlaybackParameters
    ): Boolean {
        return true
    }

    override fun isRewindEnabled(): Boolean = rewindIncrementMs > 0

    override fun isFastForwardEnabled(): Boolean = fastForwardIncrementMs > 0

    fun getRewindIncrementMs() = rewindIncrementMs

    fun getFastForwardIncrementMs() = fastForwardIncrementMs
}